/** 
 * @author    Grupo 06
 *   
 * @brief     Implements a ac_tlm video screen.
 *  
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Lesser General Public
 *   License as published by the Free Software Foundation; either
 *   version 2.1 of the License, or (at your option) any later version.
 * 
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Lesser General Public License for more details.
 * 
 * 
 */

//////////////////////////////////////////////////////////////////////////////
// Standard includes
// SystemC includes
// ArchC includes

#include "ac_tlm_vid.h"

//////////////////////////////////////////////////////////////////////////////

/// Namespace to isolate memory from ArchC
using user::ac_tlm_vid;

/// Constructor
ac_tlm_vid::ac_tlm_vid( sc_module_name module_name , int k ) :
  sc_module( module_name ),
  target_export("iport")
{
  /// Binds target_export to the video
  target_export( *this );	
  //We must first initialize the SDL video component, and check for success
  if (SDL_Init(SDL_INIT_VIDEO) != 0) {
    printf("Unable to initialize SDL: %s\n", SDL_GetError());
    exit(1);
  }

  SDL_WM_SetCaption("Urna Eletronica", NULL); // Titulo da Janela e Icone

  //- Inicializa SDL_Ttf - Usado na impressao em tela
  if(TTF_Init() < 0){
    printf("TTF_Init> %s\n", TTF_GetError());
    exit(1);
  }
  SDL_EnableUNICODE(1);


  fonte = TTF_OpenFont("assets/DejaVuSansMono.ttf", 32);
  if(!fonte){
    printf("Erro no carregamento da fonte: %s\n", TTF_GetError());
    exit(1);
  }

  atexit(TTF_Quit);
  //When this program exits, SDL_Quit must be called
  atexit(SDL_Quit);
  // cria tela
  tela = SDL_SetVideoMode(VID_WIDTH, VID_HEIGHT, 24, SDL_ANYFORMAT|SDL_FULLSCREEN);
  //	tela = SDL_SetVideoMode(VID_WIDTH, VID_HEIGHT, 24, SDL_ANYFORMAT);


  if (tela == NULL) {
    printf("Unable to set video mode: %s\n", SDL_GetError());
    exit(1);
  }

  //thread para atualizar tela
  SC_HAS_PROCESS(ac_tlm_vid);
  SC_THREAD ( atualiza );

}

/// Destructor
ac_tlm_vid::~ac_tlm_vid() {
  //destroi
  TTF_CloseFont(fonte);
  SDL_FreeSurface(tela);

}

/** Internal Write
 * Note: Always write 32 bits
 * @param a is the address to write
 * @param d is the data being written
 * @returns A TLM response packet with SUCCESS
 */
ac_tlm_rsp_status ac_tlm_vid::writev( const uint32_t &a , const uint32_t &d )
{
  int x, y; 
  if((int) a == 4*VID_WIDTH*VID_HEIGHT) {
    for(x = 0; x < VID_WIDTH; x++)
      for(y = 0; y < VID_HEIGHT; y++)
        desenhaPixel(x, y, d);
  }
  else if((int) a == 4*(VID_WIDTH*VID_HEIGHT+1)) {
    char arq[50];
    sprintf(arq, "imagens/%d.bmp", d);
    desenhaImagem(arq, 430,150);
  }
  else if((int) a > 4*(VID_WIDTH*VID_HEIGHT+2)) {
    // Imprime na tela o dado que esta na variavel d. 
    // A posicao eh passada pela variavel a recebida.
    SDL_Surface *aux;
    SDL_Color cor = {0,0,0,0};
    int k = a - 4915200;
    y = (int) ( (int)k / (VID_WIDTH * 16));
    x = (int) (((int)k % (VID_WIDTH * y))/16);
    SDL_Rect ret={x,y,0,0};
    int buf = d;
    char aimprimir [11];
    sprintf(aimprimir, "%c", d);
    aux = TTF_RenderUTF8_Blended(fonte,aimprimir,cor); 
    SDL_BlitSurface(aux,0,tela,&ret);
    SDL_FreeSurface(aux); 
  } else {
    x = (int) ( (int)a % VID_WIDTH );
    y = (int) ( (int)a / VID_WIDTH );
    desenhaPixel(x, y, d);
  }
}

void ac_tlm_vid::atualiza() // fica sempre ativo, atualiza tela
{ 
  while(1) {
    wait( 10000,SC_NS );
    SDL_Flip(tela);
  }
}

void ac_tlm_vid::desenhaPixel(int x, int y, const uint32_t &cor) {
  Uint8 *pixel;

  pixel = (Uint8 *) tela->pixels;
  pixel += (y * tela->pitch) + 4*x;

  if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
    pixel[0] = (cor & 0xFF0000) >> 16;
    pixel[1] = (cor & 0x00FF00) >> 8;
    pixel[2] = (cor & 0x0000FF);
  }
  else {
    pixel[2] = (cor & 0xFF0000) >> 16;
    pixel[1] = (cor & 0x00FF00) >> 8;
    pixel[0] = (cor & 0x0000FF);
  }
}

void ac_tlm_vid::desenhaImagem(const char *arq, int x, int y) {
  SDL_Surface *imagem;
  SDL_Rect pos;

  imagem = SDL_LoadBMP(arq);
  if (imagem == NULL) {
    fprintf(stderr, "Não foi possível carregar o arquivo %s: %s\n", arq, SDL_GetError());
    return;
  }

  pos.x = x;
  pos.y = y;
  pos.w = imagem->w;
  pos.h = imagem->h;
  SDL_BlitSurface(imagem, NULL, tela, &pos);

}
